// 瓶子管理
// bottle

package bottle

import (
	"api/models"
	"api/src"
	"api/utils"
	"encoding/base64"
	"io"
	"os"
	"strings"
	"time"

	"github.com/beego/beego/v2/core/logs"
	b "github.com/beego/beego/v2/server/web"
)

type BottleC struct {
	src.BaseC
}

func (c BottleC) Search() {
	// 只返回当前用户发布的内容，同时避免返回 userId 字段，防止前端恶意提交。
	c.Read(src.ReadParams{
		Model: models.Bottle{},
		Field: "id," +
			"name,useFor," +
			"price,tag," +
			"color,brand," +
			"height,width," +
			"sequ,remark," +
			"images,addTime," +
			"num0,num1,num2",
		Sort: "sequ desc, addTime desc",
		Filter: src.Filter{
			Query: map[string]interface{}{
				"userId": c.UserId,
			},
		},
	})
}

func (c BottleC) Add() {
	data := map[string]interface{}{
		// userId 字段值固定为当前会话的 userId，防止前端恶意提交。
		"userId":  c.UserId,
		"num0":    0,
		"num1":    0,
		"num2":    0,
		"addTime": utils.MyTime{time.Now()},
	}
	c.Create(&models.Bottle{}, data)
}

func (c BottleC) Edit() {
	data := map[string]interface{}{
		// userId 字段值固定为当前会话的 userId，防止前端恶意篡改。
		"userId": c.UserId,
	}
	c.Update(models.Bottle{}, data)
}

func (c BottleC) Remove() {
	// 删除用户之前上传的图片(images字段)
	// 首先获取 images 字段的值
	table, errMsg := c.ReadData(src.ReadParams{
		Model: models.Bottle{},
		Field: "images",
		Filter: src.Filter{
			PageSize: 1,
			Query: map[string]interface{}{
				"id": c.GetString("ids"),
			},
		},
	})
	if errMsg != "" {
		c.ServerJSON(src.Msg{false, errMsg}, 500)
		return
	}

	if table.Total == 0 {
		c.ServerJSON(src.Msg{false, "要删除的记录不存在，请刷新页面。"}, 400)
		return
	}

	images := table.TableData[0]["images"].(string)
	imageData := strings.Split(images, ",")
	for _, filePath := range imageData {
		errMsg = removeFile(filePath, c.UserId)
		if errMsg != "" {
			c.ServerJSON(src.Msg{false, errMsg}, 500)
			return
		}
	}

	c.Del(models.Bottle{})
}

// Upload 上传瓶子照片
// 请求参数：ext: jpg | mp4, b64: string, b64thumb: string
func (c BottleC) Upload() {
	data := map[string]string{}
	err := c.BindJSON(&data)
	if err != nil {
		logs.Error("BindJSON发生错误：", err)
		c.ServerJSON(src.Msg{false, "BindJSON发生错误：" + err.Error()}, 500)
		return
	}

	ext := data["ext"]
	b64 := data["b64"]
	b64thumb := data["b64thumb"]
	if ext == "" {
		c.ServerJSON(src.Msg{false, "文件扩展名不能为空"}, 400)
		return
	}

	exts := "jpg,mp4"
	if strings.Index(exts, ext) == -1 {
		c.ServerJSON(src.Msg{false, "请上传jpg图片或mp4视频，不接受其它格式。"}, 400)
		return
	}

	imgData := []byte{}
	thumbData := []byte{}
	if ext == "jpg" {
		if b64 == "" {
			c.ServerJSON(src.Msg{false, "图片数据不能为空"}, 400)
			return
		}

		if b64thumb == "" {
			c.ServerJSON(src.Msg{false, "缩略图数据不能为空"}, 400)
			return
		}

		imgData, err = base64.StdEncoding.DecodeString(b64)
		if err != nil {
			logs.Error("源图格式不正确", err)
			c.ServerJSON(src.Msg{false, "源图格式不正确" + err.Error()}, 400)
			return
		}

		thumbData, err = base64.StdEncoding.DecodeString(b64thumb)
		if err != nil {
			logs.Error("缩略图格式不正确", err)
			c.ServerJSON(src.Msg{false, "缩略图格式不正确" + err.Error()}, 400)
			return
		}
	}

	uploadDir, _ := b.AppConfig.String("uploadDir")
	appName := b.BConfig.AppName
	extMap := map[string]string{"jpg": "image", "mp4": "video"}
	extName := extMap[ext]
	uid := utils.ToStr(c.UserId)
	date := time.Now().Format("2006/01/02") // 按年月日划分文件存储
	uploadPath := uploadDir + "/" + appName + "/" + extName + "/" + uid + "/" + date
	err = utils.CreateChildDir(uploadPath)
	if err != nil {
		c.ServerJSON(src.Msg{false, "在创建上传文件夹时发生错误：" + err.Error()}, 500)
		return
	}

	if ext == "jpg" {
		// 上传图片
		timeStr := time.Now().Format("150405")

		// 检查即将保存的文件是否已经存在。若存在，则另起一个文件名。确保不要覆盖已有的文件。
		var i int8
		for i = -1; i < 10; i += 1 {
			probe := uploadPath + "/" + timeStr
			if i >= 0 {
				probe += utils.ToStr(i)
			}
			probe += "." + ext
			if !utils.IsExistPath(probe) {
				break
			}
		}
		if i >= 0 {
			timeStr += utils.ToStr(i)
		}

		fileName := timeStr + "." + ext
		file, err := os.Create(uploadPath + "/" + fileName)
		if err != nil {
			logs.Error("创建图片文件发生错误", err)
			c.ServerJSON(src.Msg{false, "创建图片文件发生错误：" + err.Error()}, 500)
			return
		}

		_, err = io.WriteString(file, string(imgData))
		_ = file.Close()
		if err != nil {
			logs.Error("保存图片文件发生错误", err)
			c.ServerJSON(src.Msg{false, "保存图片文件发生错误：" + err.Error()}, 500)
			return
		}

		// 上传缩略图
		thumbName := timeStr + "_thumb." + ext
		file, err = os.Create(uploadPath + "/" + thumbName)
		if err != nil {
			logs.Error("创建缩略图文件发生错误", err)
			c.ServerJSON(src.Msg{false, "创建缩略图文件发生错误：" + err.Error()}, 500)
			return
		}

		_, err = io.WriteString(file, string(thumbData))
		_ = file.Close()
		if err != nil {
			logs.Error("保存缩略图文件发生错误", err)
			c.ServerJSON(src.Msg{false, "保存缩略图文件发生错误：" + err.Error()}, 500)
			return
		}

		// 保存上传记录
		filePath := extName + "/" + uid + "/" + date + "/" + fileName
		inputData := map[string]interface{}{
			"userId":   c.UserId,
			"filePath": filePath,
			"addTime":  utils.MyTime{time.Now()},
		}
		errMsg := src.SaveData("新增", models.UploadHistory{}, inputData)
		if errMsg != "" {
			c.ServerJSON(src.Msg{false, errMsg}, 500)
			return
		}

		c.ServerJSON(src.Msg{true, filePath})
		return
	}

	// 上传视频
	c.Ctx.WriteString("Upload")
}

// RemoveFile 删除瓶子照片
// 请求参数：filePath = image/1/2025/10/28/222610.jpg
func (c BottleC) RemoveFile() {
	filePath := c.GetString("filePath")
	if filePath == "" {
		c.ServerJSON(src.Msg{false, "文件路径不能为空"}, 400)
		return
	}

	// 安全检查
	exts := "jpg,mp4"
	arr := strings.Split(filePath, ".")
	ext := arr[len(arr)-1]
	if strings.Index(exts, ext) == -1 {
		c.ServerJSON(src.Msg{false, "只能删除jpg图片或mp4视频，不接受其它格式。"}, 400)
		return
	}

	if strings.Index(filePath, "../") >= 0 {
		// 防止恶意删除上级文件
		filePath = strings.ReplaceAll(filePath, "../", "")
	}

	// 在删除文件之前，检查之前的上传记录是否存在，作为删除依据。
	table, errMsg := c.ReadData(src.ReadParams{
		Model: models.UploadHistory{},
		Filter: src.Filter{
			Query: map[string]interface{}{
				"userId": c.UserId, "filePath": filePath,
			},
		},
	})
	if errMsg != "" {
		c.ServerJSON(src.Msg{false, errMsg}, 500)
		return
	}

	// 拦一下，防止前端任意删除文件！
	if table.Total == 0 {
		c.ServerJSON(src.Msg{false, "要删除的文件不存在"}, 404)
		return
	}

	// 执行删除操作
	errMsg = removeFile(filePath, c.UserId)
	if errMsg != "" {
		c.ServerJSON(src.Msg{false, errMsg}, 500)
		return
	}

	c.ServerJSON(src.Msg{true, "文件删除成功"})
}

func removeFile(filePath string, userId uint32) (errMsg string) {
	// 开始删除文件
	uploadDir, _ := b.AppConfig.String("uploadDir")
	appName := b.BConfig.AppName
	uploadPath := uploadDir + "/" + appName
	if !utils.IsExistPath(uploadPath + "/" + filePath) {
		logs.Warn("要删除的文件不存在", uploadPath+"/"+filePath)
		return "要删除的文件不存在"
	}

	err := os.Remove(uploadPath + "/" + filePath)
	if err != nil {
		logs.Error("删除文件发生错误：", err)
		return "删除文件发生错误：" + err.Error()
	}

	// 删除缩略图
	fileName := strings.Split(filePath, ".")
	thumbPath := fileName[0] + "_thumb." + fileName[1]
	if utils.IsExistPath(uploadPath + "/" + thumbPath) {
		err = os.Remove(uploadPath + "/" + thumbPath)
		if err != nil {
			logs.Error("删除缩略图发生错误：", err)
			return "删除缩略图发生错误：" + err.Error()
		}
	}

	// 删除文件后清理多余的空文件夹
	err = utils.RemoveEmptyDir(uploadPath)
	if err != nil {
		logs.Error("在清理空文件夹时发生错误：", err)
		return "在清理空文件夹时发生错误：" + err.Error()
	}

	// 删除之前的上传记录
	uid := utils.ToStr(userId)
	condition := "userId=" + uid + " and filePath='" + filePath + "'"
	errMsg = src.DeleteData(models.UploadHistory{}, condition)
	return errMsg
}

// StockIn 0 新瓶入库
// 请求参数：id=1,num=1
func (c BottleC) StockIn() {
	id, err := c.GetUint32("id", 0)
	if err != nil {
		c.ServerJSON(src.Msg{false, err.Error()}, 400)
		return
	}

	num, err := c.GetUint32("num", 0)
	if err != nil {
		c.ServerJSON(src.Msg{false, err.Error()}, 400)
		return
	}

	query := map[string]interface{}{
		"userId": c.UserId, "id": id,
	}
	table, errMsg := c.ReadData(src.ReadParams{
		Model:  models.Bottle{},
		Filter: src.Filter{Query: query},
	})
	if errMsg != "" {
		c.ServerJSON(src.Msg{false, errMsg}, 500)
		return
	}

	if len(table.TableData) == 0 {
		c.ServerJSON(src.Msg{false, "查无此物"}, 404)
		return
	}

	// 更新台帐
	data := map[string]interface{}{
		"id":   id,
		"num0": table.TableData[0]["num0"].(uint32) + num,
	}
	errMsg = src.SaveData("编辑", models.Bottle{}, data)
	if errMsg != "" {
		c.ServerJSON(src.Msg{false, errMsg}, 500)
		return
	}

	// 插入流水帐
	data = map[string]interface{}{
		"userId":   c.UserId,
		"bottleId": id,
		"action":   0,
		"num":      num,
		"addTime":  utils.MyTime{time.Now()},
	}
	errMsg = src.SaveData("新增", models.Journal{}, data)
	if errMsg != "" {
		c.ServerJSON(src.Msg{false, errMsg}, 500)
		return
	}

	c.ServerJSON(src.Msg{true, "入库成功"})
}

// TakeUp 1 上架
func (c BottleC) TakeUp() {
	id, err := c.GetUint32("id", 0)
	if err != nil {
		c.ServerJSON(src.Msg{false, err.Error()}, 400)
		return
	}

	num, err := c.GetUint32("num", 0)
	if err != nil {
		c.ServerJSON(src.Msg{false, err.Error()}, 400)
		return
	}

	query := map[string]interface{}{
		"userId": c.UserId, "id": id,
	}
	table, errMsg := c.ReadData(src.ReadParams{
		Model:  models.Bottle{},
		Filter: src.Filter{Query: query},
	})
	if errMsg != "" {
		c.ServerJSON(src.Msg{false, errMsg}, 500)
		return
	}

	if len(table.TableData) == 0 {
		c.ServerJSON(src.Msg{false, "查无此物"}, 404)
		return
	}

	// 检查流水帐里是否有前一动作的记录
	query = map[string]interface{}{
		"userId": c.UserId, "bottleId": id, "action": 0,
	}
	journal, errMsg := c.ReadData(src.ReadParams{
		Model:  models.Journal{},
		Filter: src.Filter{Query: query},
	})
	if errMsg != "" {
		c.ServerJSON(src.Msg{false, errMsg}, 500)
		return
	}

	if len(journal.TableData) == 0 {
		c.ServerJSON(src.Msg{false, "流水帐里没有前一动作的记录"}, 404)
		return
	}

	// 更新台帐
	data := map[string]interface{}{
		"id":   id,
		"num0": table.TableData[0]["num0"].(uint32) - num,
		"num1": table.TableData[0]["num1"].(uint32) + num,
	}
	errMsg = src.SaveData("编辑", models.Bottle{}, data)
	if errMsg != "" {
		c.ServerJSON(src.Msg{false, errMsg}, 500)
		return
	}

	// 插入流水帐
	data = map[string]interface{}{
		"userId":   c.UserId,
		"bottleId": id,
		"action":   1,
		"num":      num,
		"addTime":  utils.MyTime{time.Now()},
	}
	errMsg = src.SaveData("新增", models.Journal{}, data)
	if errMsg != "" {
		c.ServerJSON(src.Msg{false, errMsg}, 500)
		return
	}

	c.ServerJSON(src.Msg{true, "上架成功"})
}

// Dispose 2 售出
func (c BottleC) Dispose() {
	id, err := c.GetUint32("id", 0)
	if err != nil {
		c.ServerJSON(src.Msg{false, err.Error()}, 400)
		return
	}

	num, err := c.GetUint32("num", 0)
	if err != nil {
		c.ServerJSON(src.Msg{false, err.Error()}, 400)
		return
	}

	query := map[string]interface{}{
		"userId": c.UserId, "id": id,
	}
	table, errMsg := c.ReadData(src.ReadParams{
		Model:  models.Bottle{},
		Filter: src.Filter{Query: query},
	})
	if errMsg != "" {
		c.ServerJSON(src.Msg{false, errMsg}, 500)
		return
	}

	if len(table.TableData) == 0 {
		c.ServerJSON(src.Msg{false, "查无此物"}, 404)
		return
	}

	// 检查流水帐里是否有前一动作的记录
	query = map[string]interface{}{
		"userId":   c.UserId,
		"bottleId": id,
		"action":   1,
	}
	journal, errMsg := c.ReadData(src.ReadParams{
		Model:  models.Journal{},
		Filter: src.Filter{Query: query},
	})
	if errMsg != "" {
		c.ServerJSON(src.Msg{false, errMsg}, 500)
		return
	}

	if len(journal.TableData) == 0 {
		c.ServerJSON(src.Msg{false, "流水帐里没有前一动作的记录"}, 404)
		return
	}

	// 更新台帐
	data := map[string]interface{}{
		"id":   id,
		"num1": table.TableData[0]["num1"].(uint32) - num,
		"num2": table.TableData[0]["num2"].(uint32) + num,
	}
	errMsg = src.SaveData("编辑", models.Bottle{}, data)
	if errMsg != "" {
		c.ServerJSON(src.Msg{false, errMsg}, 500)
		return
	}

	// 插入流水帐
	data = map[string]interface{}{
		"userId":   c.UserId,
		"bottleId": id,
		"action":   2,
		"num":      num,
		"addTime":  utils.MyTime{time.Now()},
	}
	errMsg = src.SaveData("新增", models.Journal{}, data)
	if errMsg != "" {
		c.ServerJSON(src.Msg{false, errMsg}, 500)
		return
	}

	c.ServerJSON(src.Msg{true, "售出成功"})
}

// TakeDown 3 下架返库
func (c BottleC) TakeDown() {
	id, err := c.GetUint32("id", 0)
	if err != nil {
		c.ServerJSON(src.Msg{false, err.Error()}, 400)
		return
	}

	num, err := c.GetUint32("num", 0)
	if err != nil {
		c.ServerJSON(src.Msg{false, err.Error()}, 400)
		return
	}

	query := map[string]interface{}{
		"userId": c.UserId, "id": id,
	}
	table, errMsg := c.ReadData(src.ReadParams{
		Model:  models.Bottle{},
		Filter: src.Filter{Query: query},
	})
	if errMsg != "" {
		c.ServerJSON(src.Msg{false, errMsg}, 500)
		return
	}

	if len(table.TableData) == 0 {
		c.ServerJSON(src.Msg{false, "查无此物"}, 404)
		return
	}

	// 检查流水帐里是否有前一动作的记录
	query = map[string]interface{}{
		"userId": c.UserId, "bottleId": id, "action": 1,
	}
	journal, errMsg := c.ReadData(src.ReadParams{
		Model:  models.Journal{},
		Filter: src.Filter{Query: query},
	})
	if errMsg != "" {
		c.ServerJSON(src.Msg{false, errMsg}, 500)
		return
	}

	if len(journal.TableData) == 0 {
		c.ServerJSON(src.Msg{false, "流水帐里没有前一动作的记录"}, 404)
		return
	}

	// 更新台帐
	data := map[string]interface{}{
		"id":   id,
		"num1": table.TableData[0]["num1"].(uint32) - num,
		"num0": table.TableData[0]["num0"].(uint32) + num,
	}
	errMsg = src.SaveData("编辑", models.Bottle{}, data)
	if errMsg != "" {
		c.ServerJSON(src.Msg{false, errMsg}, 500)
		return
	}

	// 插入流水帐
	data = map[string]interface{}{
		"userId":   c.UserId,
		"bottleId": id,
		"action":   3,
		"num":      num,
		"addTime":  utils.MyTime{time.Now()},
	}
	errMsg = src.SaveData("新增", models.Journal{}, data)
	if errMsg != "" {
		c.ServerJSON(src.Msg{false, errMsg}, 500)
		return
	}

	c.ServerJSON(src.Msg{true, "下架成功"})
}

// Abandon 4 丢弃
func (c BottleC) Abandon() {
	id, err := c.GetUint32("id", 0)
	if err != nil {
		c.ServerJSON(src.Msg{false, err.Error()}, 400)
		return
	}

	num, err := c.GetUint32("num", 0)
	if err != nil {
		c.ServerJSON(src.Msg{false, err.Error()}, 400)
		return
	}

	query := map[string]interface{}{
		"userId": c.UserId, "id": id,
	}
	table, errMsg := c.ReadData(src.ReadParams{
		Model:  models.Bottle{},
		Filter: src.Filter{Query: query},
	})
	if errMsg != "" {
		c.ServerJSON(src.Msg{false, errMsg}, 500)
		return
	}

	if len(table.TableData) == 0 {
		c.ServerJSON(src.Msg{false, "查无此物"}, 404)
		return
	}

	// 检查流水帐里是否有前一动作的记录
	query = map[string]interface{}{
		"userId": c.UserId, "bottleId": id, "action": 0,
	}
	journal, errMsg := c.ReadData(src.ReadParams{
		Model:  models.Journal{},
		Filter: src.Filter{Query: query},
	})
	if errMsg != "" {
		c.ServerJSON(src.Msg{false, errMsg}, 500)
		return
	}

	if len(journal.TableData) == 0 {
		c.ServerJSON(src.Msg{false, "流水帐里没有前一动作的记录"}, 404)
		return
	}

	// 更新台帐
	data := map[string]interface{}{
		"id":   id,
		"num0": table.TableData[0]["num0"].(uint32) - num,
	}
	errMsg = src.SaveData("编辑", models.Bottle{}, data)
	if errMsg != "" {
		c.ServerJSON(src.Msg{false, errMsg}, 500)
		return
	}

	// 插入流水帐
	data = map[string]interface{}{
		"userId":   c.UserId,
		"bottleId": id,
		"action":   4,
		"num":      num,
		"addTime":  utils.MyTime{time.Now()},
	}
	errMsg = src.SaveData("新增", models.Journal{}, data)
	if errMsg != "" {
		c.ServerJSON(src.Msg{false, errMsg}, 500)
		return
	}

	c.ServerJSON(src.Msg{true, "丢弃成功"})
}
